
#include "fileParseTools.h"

int8_t findSpec(uint8_t c)
{
    uint8_t spec[] = {'<', '>'};
    uint16_t len = sizeof(spec) / sizeof(spec[0]);
    for (int i = 0; i < len; i++)
    {
        if (c == spec[i])
        {
            return 0;
        }
    }

    return -1;
}

#define MAXSTRING_LEN 50          // 最小内容长度,和内存扩展步进
#define MEMORY_EXPANSION_MARGIN 5 // 内存扩展余量余量,留下一定空间填充结束字符和扩展临界值
typedef enum
{
    ISLAB_UNKNOWN = -1, // 未知
    ISLAB_START,        // 标签段开始
    ISLAB_STOP,         // 标签段结束
} isLab_e;
typedef struct
{
    uint8_t *context;    // 获取一段标签内容
    isLab_e isLab;       // 参考 isLab_e
    int8_t memExtCount;  // 猜测到有可能一段标签内容巨大,所以增加可扩展
    uint32_t labelIndex; // 长度,用于字节加入保存
} lineParse_t;
static lineParse_t s_lineParse = {0};
int8_t getLine(uint8_t c)
{

    if (s_lineParse.context == NULL)
    {
        memset(&s_lineParse, 0, sizeof(lineParse_t)); // 初始化所有参数
        s_lineParse.context = (uint8_t *)malloc(MAXSTRING_LEN);
        memset(s_lineParse.context, 0, MAXSTRING_LEN);
        s_lineParse.isLab = ISLAB_UNKNOWN;
        s_lineParse.labelIndex = 0;
        s_lineParse.memExtCount = 1;
    }

    if (findSpec(c) == 0)
    {
        if (c == '<')
        {
            s_lineParse.isLab = ISLAB_START;
        }
        else if (c == '>')
        {
            s_lineParse.isLab = ISLAB_STOP;
        }
    }
    else
    {
        if (s_lineParse.isLab == ISLAB_STOP)
        {
            uint16_t len = s_lineParse.labelIndex;
            s_lineParse.context[s_lineParse.labelIndex] = '\0';
            printf("--->[%s] len %d\n", s_lineParse.context, len);
            parseLineContent(s_lineParse.context, len);
            memset(s_lineParse.context, 0, MAXSTRING_LEN * s_lineParse.memExtCount);
            s_lineParse.labelIndex = 0;
            s_lineParse.isLab = ISLAB_UNKNOWN;
        }
        else if (s_lineParse.isLab == ISLAB_START)
        {

            // 空间不足，扩展空间
            if (s_lineParse.labelIndex > MAXSTRING_LEN * s_lineParse.memExtCount - MEMORY_EXPANSION_MARGIN)
            {

                s_lineParse.memExtCount++;
                s_lineParse.context = realloc(s_lineParse.context, MAXSTRING_LEN * s_lineParse.memExtCount);
                // printf("--> space is not enough --- realloc %d  index %d addr %c\n", MAXSTRING_LEN * memExtCount, labelIndex, context[labelIndex]);

                if (s_lineParse.context == NULL)
                {
                    printf("error !!!\n");
                    return -1;
                }
            }

            // 保存内容
            s_lineParse.context[s_lineParse.labelIndex] = c;
            s_lineParse.labelIndex++;
        }
    }

    return 0;
}

#define MAXPARAMS_COUNT 50 // 一个标签段最大可容纳参数个数
typedef enum
{
    FINDLABELSTEP_UNKNOWN,     // 未知,一般在查找标签名
    FINDLABELSTEP_LABELNAME,   // 查找标签结束
    FINDLABELSTEP_PARAM_NAME,  // 查找参数名
    FINDLABELSTEP_PARAM_VALUE, // 查找参数值
} findLabelStep_e;
typedef struct
{
    uint8_t *labelName;                   // 保存标签名
    uint32_t len, exMemCount, paramIndex; // 必要参数
    uint8_t *params[MAXPARAMS_COUNT];     // 参数名称解析后存放指针
    uint8_t *paramValue[MAXPARAMS_COUNT]; // 参数内容解析后存放指针
} xml_label_t;

static xml_label_t s_xml_label = {0};

// 解析上面获取的单一行内容，分别归类
int8_t parseLineContent(uint8_t *str, uint16_t strLen)
{
    // printf("<%s>\n", str);

    if (s_xml_label.labelName == NULL)
    {
        memset(&s_xml_label, 0, sizeof(xml_label_t)); // 初始化所有参数
        s_xml_label.labelName = (uint8_t *)malloc(MAXSTRING_LEN);
        memset(s_xml_label.labelName, 0, MAXSTRING_LEN);
        s_xml_label.exMemCount = 1;
        s_xml_label.paramIndex = 0;
        s_xml_label.len = 0;

        uint16_t paramsCount = sizeof(s_xml_label.params) / sizeof(s_xml_label.params[0]);
        for (uint16_t i = 0; i < paramsCount; i++)
        {
            s_xml_label.params[i] = NULL;
        }

        paramsCount = sizeof(s_xml_label.paramValue) / sizeof(s_xml_label.paramValue[0]);
        for (uint16_t i = 0; i < paramsCount; i++)
        {
            s_xml_label.paramValue[i] = NULL;
        }
    }

    //
    printf("strlen %d\n", strLen);
    findLabelStep_e findStep = FINDLABELSTEP_UNKNOWN;
    bool running = false, valueStart = false;

    for (uint16_t i = 0; i < strLen; i++)
    {
        if (str[i] == ' ' && valueStart == false)
        {
            if (findStep == FINDLABELSTEP_UNKNOWN)
            {
                findStep = FINDLABELSTEP_LABELNAME;
                running = false;
            }
            // else if (findStep == FINDLABELSTEP_PARAM_VALUE)
            // {
            //     findStep = FINDLABELSTEP_PARAM_NAME;
            //     running = false;
            // }
        }
        else if (str[i] == '=' && valueStart == false)
        {

            if (findStep == FINDLABELSTEP_PARAM_NAME)
            {
                running = false;
            }
            if (findStep == FINDLABELSTEP_PARAM_VALUE)
            {
                running = false;
            }
        }
        else if (str[i] == '\"')
        {

            if (findStep == FINDLABELSTEP_PARAM_VALUE)
            {
                if (valueStart == true)
                {
                    valueStart = false;
                }

                running = false;
            }
        }
        else
        {
            // 分配空间参数重置
            if (running == false)
            {
                if (findStep == FINDLABELSTEP_LABELNAME)
                {
                    s_xml_label.labelName[s_xml_label.len] = '\0';
                    // printf("lb [%s]\n", s_xml_label.labelName);
                    s_xml_label.len = 0;
                    s_xml_label.exMemCount = 1;
                    findStep = FINDLABELSTEP_PARAM_NAME;
                }
                else if (findStep == FINDLABELSTEP_PARAM_NAME)
                {
                    s_xml_label.params[s_xml_label.paramIndex][s_xml_label.len] = '\0';
                    // printf("pn [%d] [%s]\n", s_xml_label.paramIndex, s_xml_label.params[s_xml_label.paramIndex]);
                    s_xml_label.len = 0;
                    s_xml_label.exMemCount = 1;

                    //
                    findStep = FINDLABELSTEP_PARAM_VALUE;
                    valueStart = true;
                }
                else if (findStep == FINDLABELSTEP_PARAM_VALUE)
                {
                    s_xml_label.paramValue[s_xml_label.paramIndex][s_xml_label.len] = '\0';
                    // printf("pv [%d] [%s]\n", s_xml_label.paramIndex, s_xml_label.paramValue[s_xml_label.paramIndex]);
                    s_xml_label.len = 0;
                    s_xml_label.exMemCount = 1;

                    //
                    findStep = FINDLABELSTEP_PARAM_NAME;
                    s_xml_label.paramIndex++;
                    valueStart = false;
                }

                running = true;
            }

            // 查找标签名
            if (findStep == FINDLABELSTEP_UNKNOWN)
            {
                // 空间不足，扩展空间
                if (s_xml_label.len > MAXSTRING_LEN * s_xml_label.exMemCount - MEMORY_EXPANSION_MARGIN)
                {
                    s_xml_label.exMemCount++;
                    s_xml_label.labelName = realloc(s_xml_label.labelName, MAXSTRING_LEN * s_xml_label.exMemCount);
                    // printf("--> space is not enough --- realloc %d  index %d addr %c\n", MAXSTRING_LEN * memExtCount, labelIndex, context[labelIndex]);

                    if (s_xml_label.labelName == NULL)
                    {
                        printf("error !!!\n");
                        break;
                    }
                }
                s_xml_label.labelName[s_xml_label.len] = str[i];
                s_xml_label.len++;
            }

            // 查找参数名
            else if (findStep == FINDLABELSTEP_PARAM_NAME)
            {
                if (s_xml_label.params[s_xml_label.paramIndex] == NULL)
                {
                    s_xml_label.params[s_xml_label.paramIndex] = (uint8_t *)malloc(MAXSTRING_LEN);
                    memset(s_xml_label.params[s_xml_label.paramIndex], 0, MAXSTRING_LEN);
                }

                if (s_xml_label.len > MAXSTRING_LEN * s_xml_label.exMemCount - MEMORY_EXPANSION_MARGIN)
                {
                    s_xml_label.exMemCount++;
                    s_xml_label.params[s_xml_label.paramIndex] = realloc(s_xml_label.params[s_xml_label.paramIndex], MAXSTRING_LEN * s_xml_label.exMemCount);
                    // printf("--> space is not enough --- realloc %d  index %d addr %c\n", MAXSTRING_LEN * memExtCount, labelIndex, context[labelIndex]);

                    if (s_xml_label.params[s_xml_label.paramIndex] == NULL)
                    {
                        printf("error !!!\n");
                        break;
                    }
                }

                s_xml_label.params[s_xml_label.paramIndex][s_xml_label.len] = str[i];
                s_xml_label.len++;
            }

            // 查找参数值
            else if (findStep == FINDLABELSTEP_PARAM_VALUE)
            {
                if (s_xml_label.paramValue[s_xml_label.paramIndex] == NULL)
                {
                    s_xml_label.paramValue[s_xml_label.paramIndex] = (uint8_t *)malloc(MAXSTRING_LEN);
                    memset(s_xml_label.paramValue[s_xml_label.paramIndex], 0, MAXSTRING_LEN);
                }

                if (s_xml_label.len > MAXSTRING_LEN * s_xml_label.exMemCount - MEMORY_EXPANSION_MARGIN)
                {
                    s_xml_label.exMemCount++;
                    s_xml_label.paramValue[s_xml_label.paramIndex] = realloc(s_xml_label.paramValue[s_xml_label.paramIndex], MAXSTRING_LEN * s_xml_label.exMemCount);
                    // printf("--> space is not enough --- realloc %d  index %d addr %c\n", MAXSTRING_LEN * memExtCount, labelIndex, context[labelIndex]);

                    if (s_xml_label.paramValue[s_xml_label.paramIndex] == NULL)
                    {
                        printf("error !!!\n");
                        break;
                    }
                }

                s_xml_label.paramValue[s_xml_label.paramIndex][s_xml_label.len] = str[i];
                s_xml_label.len++;
            }
        }
        // printf("[%c] ", str[i]);
        // printf("valueStart %d running %d findStep %d  s_xml_label.len %d s_xml_label.paramIndex %d s_xml_label.exMemCount %d\n",
        //        valueStart,
        //        running,
        //        findStep,
        //        s_xml_label.len,
        //        s_xml_label.paramIndex,
        //        s_xml_label.exMemCount);
    }

    // 释放资源
    if (s_xml_label.labelName != NULL)
    {
        printf("labelName: %s\n", s_xml_label.labelName);
        free(s_xml_label.labelName);
        s_xml_label.labelName = NULL;
    }

    uint16_t paramsCount = sizeof(s_xml_label.params) / sizeof(s_xml_label.params[0]);
    for (uint16_t i = 0; i < paramsCount; i++)
    {
        if (s_xml_label.params[i] != NULL)
        {
            printf("param[%d] name [%s]\n", i, s_xml_label.params[i]);
            free(s_xml_label.params[i]);
            s_xml_label.params[i] = NULL;
        }
    }
    paramsCount = sizeof(s_xml_label.paramValue) / sizeof(s_xml_label.paramValue[0]);
    for (uint16_t i = 0; i < paramsCount; i++)
    {
        if (s_xml_label.paramValue[i] != NULL)
        {
            printf("param[%d] value [%s]\n", i, s_xml_label.paramValue[i]);
            free(s_xml_label.paramValue[i]);
            s_xml_label.paramValue[i] = NULL;
        }
    }

    memset(&s_xml_label, 0, sizeof(xml_label_t));
    return 0;
}

int main(int argc, char *argv[])
{
    printf("param count %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("param[%d] %s\n", i, argv[i]);
    }

    if (argc < 2)
    {
        printf("This tool is only used to parse xml files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.xm\n");
        return 0;
    }

    if ((strcmp(argv[1], "help") == 0) || (strcmp(argv[1], "-h") == 0))
    {
        printf("This tool is only used to parse xml files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.xm\n");
        return 0;
    }

    FILE *file = NULL;
    file = fopen(argv[1], "rb");
    if (file == NULL)
    {
        printf("open file fail\n");
        return -1;
    }

    uint8_t c = ' ';

    while (!feof(file))
    {
        c = fgetc(file);
        getLine(c);
    }

    if (s_lineParse.context != NULL)
    {
        free(s_lineParse.context);
        s_lineParse.context = NULL;
    }

    printf("parse ok!\n");
    fclose(file);
    return 0;
}
